#!/bin/sh

add_snat_chain() {
  /sbin/iptables -t nat -N $1_post
  /sbin/iptables -t nat -I POSTROUTING -j $1_post
}

add_dnat_chain() {
  /sbin/iptables -t nat -N $1_pre
  /sbin/iptables -t nat -I PREROUTING -j $1_pre
}

del_chain() {
  /sbin/iptables -t nat -D PREROUTING -j $1_pre
  /sbin/iptables -t nat -D POSTROUTING -j $1_post
  /sbin/iptables -t nat -F $1_pre
  /sbin/iptables -t nat -X $1_pre
  /sbin/iptables -t nat -F $1_post
  /sbin/iptables -t nat -X $1_post
}

MOD_NAME=nat
MOD_DEFAULTS=/opt/$MOD_NAME/etc/defaults
MOD_SETTINGS=/opt/$MOD_NAME/etc/settings
[ -L "$MOD_SETTINGS" ] && MOD_SETTINGS=`readlink $MOD_SETTINGS`

IPT_SNAT_ADD="iptables -t nat -A mod_nat_post"
IPT_SNAT_DEL="iptables -t nat -D mod_nat_post"
IPT_DNAT_ADD="iptables -t nat -A mod_nat_pre"
IPT_DNAT_DEL="iptables -t nat -D mod_nat_pre"

[ -f "$MOD_SETTINGS" ] || cp $MOD_DEFAULTS $MOD_SETTINGS
[ -x "/sbin/hash_verify" ] && [ ! -f "$MOD_SETTINGS.hash" ] && cp $MOD_DEFAULTS.hash $MOD_SETTINGS.hash

. $MOD_SETTINGS

case "$1" in

  start)
    [ -x "/sbin/hash_verify" ] && ! hash_verify $MOD_SETTINGS && exit 1
    echo -n "Starting module $MOD_NAME: "
    if [ "$MOD_NAT_SNAT_ENABLED" != "1" ] && [ "$MOD_NAT_DNAT_ENABLED" != "1" ]; then
      echo "skipped"
      exit 0
    fi
    RETVAL=0
    if [ "$MOD_NAT_SNAT_ENABLED" = "1" ]; then
      add_snat_chain mod_nat
      i=1
      while [ $i -le 64 ]; do
        eval ENABLED='$'MOD_NAT_SNAT_RULE$((i))_ENABLED
        if [ "$ENABLED" = "1" ]; then
          eval TMP='$'MOD_NAT_SNAT_RULE$((i))_PROTO
          [ -n "$TMP" ] && PROTOS="${TMP//[_]/ }" || PROTOS="NA"
          for PROTO in $PROTOS; do
            [ "$PROTO" != "NA" ] && PROTO="-p $PROTO" || PROTO=""
            eval TMP='$'MOD_NAT_SNAT_RULE$((i))_IF
            [ -n "$TMP" ] && IF="-o $TMP" || IF=""
            eval TMP='$'MOD_NAT_SNAT_RULE$((i))_SRC_IPADDR
            [ -n "$TMP" ] && SRC="-s $TMP" || SRC=""
            eval TMP='$'MOD_NAT_SNAT_RULE$((i))_SRC_PORT
            [ -n "$TMP" ] && SPORT="--sport $TMP" || SPORT=""
            eval TMP='$'MOD_NAT_SNAT_RULE$((i))_DST_IPADDR
            [ -n "$TMP" ] && DST="-d $TMP" || DST=""
            eval TMP='$'MOD_NAT_SNAT_RULE$((i))_DST_PORT
            [ -n "$TMP" ] && DPORT="--dport $TMP" || DPORT=""
            MATCH_PATTERN="$PROTO $IF $SRC $SPORT $DST $DPORT"
            eval TMP='$'MOD_NAT_SNAT_RULE$((i))_TO_SRC_PORT
            if [ -n "$TMP" ]; then
              eval TMP='$'MOD_NAT_SNAT_RULE$((i))_TO_SRC:'$'MOD_NAT_SNAT_RULE$((i))_TO_SRC_PORT
            else
              eval TMP='$'MOD_NAT_SNAT_RULE$((i))_TO_SRC
            fi
            echo "$TMP" | /bin/grep -q "/"; IS_SUBNET=$?
            if [ -z "$TMP" ]; then
              $IPT_SNAT_ADD $MATCH_PATTERN -j MASQUERADE 2>/dev/null || RETVAL=1
            elif [ "$IS_SUBNET" != "1" ]; then
              $IPT_SNAT_ADD $MATCH_PATTERN -j NETMAP --to $TMP 2>/dev/null || RETVAL=1
            else
              $IPT_SNAT_ADD $MATCH_PATTERN -j SNAT --to $TMP 2>/dev/null || RETVAL=1
            fi
          done
        fi
        i=$(($i+1))
      done
    fi
    if [ "$MOD_NAT_DNAT_ENABLED" = "1" ]; then
      add_dnat_chain mod_nat
      i=1
      while [ $i -le 64 ]; do
        eval ENABLED='$'MOD_NAT_DNAT_RULE$((i))_ENABLED
        if [ "$ENABLED" = "1" ]; then
          eval TMP='$'MOD_NAT_DNAT_RULE$((i))_PROTO
          [ -n "$TMP" ] && PROTOS="${TMP//[_]/ }" || PROTOS="NA"
          for PROTO in $PROTOS; do
            [ "$PROTO" != "NA" ] && PROTO="-p $PROTO" || PROTO=""
            eval TMP='$'MOD_NAT_DNAT_RULE$((i))_IF
            [ -n "$TMP" ] && IF="-i $TMP"  || IF=""
            eval TMP='$'MOD_NAT_DNAT_RULE$((i))_SRC_IPADDR
            [ -n "$TMP" ] && SRC="-s $TMP"  || SRC=""
            eval TMP='$'MOD_NAT_DNAT_RULE$((i))_SRC_PORT
            [ -n "$TMP" ] && SPORT="--sport $TMP"  || SPORT=""
            eval TMP='$'MOD_NAT_DNAT_RULE$((i))_DST_IPADDR
            [ -n "$TMP" ] && DST="-d $TMP"  || DST=""
            eval TMP='$'MOD_NAT_DNAT_RULE$((i))_DST_PORT
            [ -n "$TMP" ] && DPORT="--dport $TMP"  || DPORT=""
            MATCH_PATTERN="$PROTO $IF $SRC $SPORT $DST $DPORT"
            eval TMP='$'MOD_NAT_DNAT_RULE$((i))_TO_DST_PORT
            if [ -n "$TMP" ]; then
              eval TMP='$'MOD_NAT_DNAT_RULE$((i))_TO_DST:'$'MOD_NAT_DNAT_RULE$((i))_TO_DST_PORT
            else
              eval TMP='$'MOD_NAT_DNAT_RULE$((i))_TO_DST
            fi
            echo "$TMP" | /bin/grep -q "/"; IS_SUBNET=$?
            if [ "$IS_SUBNET" != "1" ]; then
              $IPT_DNAT_ADD $MATCH_PATTERN -j NETMAP --to $TMP 2>/dev/null || RETVAL=1
            else
              $IPT_DNAT_ADD $MATCH_PATTERN -j DNAT --to $TMP 2>/dev/null || RETVAL=1
            fi
          done
        fi
        i=$(($i+1))
      done
    fi
    if [ "$RETVAL" = "1" ]; then
      echo "failed"
      exit 1
    fi
    echo "done"
    exit 0
  ;;

  stop)
    echo -n "Stopping module $MOD_NAME: "
    del_chain mod_nat 2>/dev/null
    echo "done"
    exit 0
  ;;

  restart)
    $0 stop
    $0 start
  ;;

  status)
    if [ "$MOD_NAT_SNAT_ENABLED" != "1" ]; then
      echo "SNAT is disabled"
    else
      echo "SNAT rules:"
      iptables -t nat -vnL mod_nat_post
    fi
    if [ "$MOD_NAT_DNAT_ENABLED" != "1" ]; then
      echo ""
      echo "DNAT is disabled"
    else
      echo ""
      echo "DNAT rules:"
      iptables -t nat -vnL mod_nat_pre
    fi
    exit 0
  ;;

  defaults)
    cp $MOD_DEFAULTS $MOD_SETTINGS 2>/dev/null
    [ -f "$MOD_DEFAULTS.hash" ] && cp $MOD_DEFAULTS.hash $MOD_SETTINGS.hash
    exit 0
  ;;

  *)
    echo "Usage: $0 {start|stop|restart|status|defaults}"
    exit 1
  ;;

esac
